﻿//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//  
//  Copyright (c) 2012, Dr. Masroor Ehsan
//  All rights reserved.
//  
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the <organization> nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//  
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//  DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
//  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
//  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//  
//  $Id$
//  
//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

using Chevron.OrderDetails.Models;

namespace Chevron.OrderDetails.RefCalc
{
    public class ReferralFeeCalculator
    {
        public TestCatalog Catalog { get; set; }

        public PhysiciansCatalog Physicians { get; set; }

        public TestCategoryCatalog Categories { get; set; }

        public LabOrdersList Orders { get; set; }

        public void Calculate()
        {
            foreach (var order in Orders)
            {
                decimal refGross = 0m;
                foreach (var test in order.Tests)
                {
                    test.Referral = CalculateTestCommission(test);
                    refGross += test.Referral;
                }

                order.GrossReferral = refGross;
                order.NetReferral = CalculateNetReferral(order);
                order.Physician.UpdateFromOrder(order);
            }
        }

        private static decimal CalculateNetReferral(OrderDto order)
        {
            // Deduct the discount amount (if any) from the gross referral
            decimal refAfterDisc = (order.Discount > 0m) ? order.GrossReferral - order.Discount : order.GrossReferral;

            // If the order is fully paid
            if (order.Due == 0m || refAfterDisc < 0m)
            {
                return refAfterDisc < 0m ? 0m : refAfterDisc; // <- disallow negative balance
            }

            // We sum up test prices to obtain the actual invoice amount.
            // This will eliminate all billable items
            decimal actualBill = 0m;

            foreach (var test in order.Tests)
            {
                if (!test.IsCancelled || (test.Referral > 0m))
                {
                    actualBill += test.LabTest.Price;
                }
            }

            // decimal actualDue = actualBill - order.Payment;
            // if (actualDue <= 0m) // <- disabled adjustment
            return refAfterDisc;

            decimal percentPaid = (order.Payment*100m)/actualBill;
            decimal refAdjusted = (percentPaid*refAfterDisc)/100m;
            refAdjusted = decimal.Ceiling(refAdjusted);
            return refAdjusted;
        }

        private static decimal CalculateTestCommission(OrderDetailDto test)
        {
            if (test.IsCancelled)
                return 0m;

            switch (test.LabTest.Category.ReferalType)
            {
                case ReferalType.Flat:
                    return test.LabTest.Category.ReferalAmount;
                case ReferalType.Percent:
                    return (test.LabTest.Price*test.LabTest.Category.ReferalAmount)/100m;
                default:
                    return 0m;
            }
        }
    }
}